#include <string>

#include "monad.hpp"

// --- 6. 示例和组合 ---

int main()
{
    std::cout << "--- Writer Monad ---" << std::endl;
    auto comp_writer = bind(unit_writer<int, std::string>(5),
                            [](int x)
                            {
                                return bind(tell<std::string>("Got value " + std::to_string(x) + ". "),
                                            [=](std::monostate) { return unit_writer<int, std::string>(x * 2); });
                            });
    std::cout << "Result: " << comp_writer.value << ", Log: " << comp_writer.log << std::endl;

    std::cout << "\n--- Reader Monad ---" << std::endl;
    struct Config
    {
        int multiplier;
        std::string name;
    };
    auto comp_reader =
        bind(ask<Config>(),
             [](const Config& cfg)
             {
                 return bind(unit_reader<Config, int>(10),
                             [cfg](int x) { return unit_reader<Config, std::string>(cfg.name + " computed " + std::to_string(x * cfg.multiplier)); });
             });
    Config env{2, "MyApp"};
    std::cout << "Result: " << comp_reader.run(env) << std::endl;

    std::cout << "\n--- State Monad ---" << std::endl;
    auto comp_state = bind(get<int>(), [](int s) { return bind(put<int>(s + 1), [=](std::monostate) { return unit_state<int, int>(s * 10); }); });
    int initial_state = 5;
    auto [result_state, final_state] = comp_state.run(initial_state);
    std::cout << "Result: " << result_state << ", Final State: " << final_state << std::endl;

    std::cout << "\n--- Combined: StateT over Reader ---" << std::endl;
    // StateT<Reader<Config, *>, int, T> -> State that also reads Config
    auto comp_combined = bind(gett<Identity, int>(), [](int s) { // StateT<Identity, int, int>
        return bind(askt<Identity, Config>(), [s](const Config& cfg) { // ReaderT<Identity, Config, Config>
             return bind(unit_statet<Identity, int>(s * cfg.multiplier), [](int res) { // StateT<Identity, int, int>
                 return bind(putt<Identity, int>(res), [=](std::monostate) { // StateT<Identity, int, void>
                     return unit_statet<Identity, int>(res + 100); // StateT<Identity, int, int>
                 });
             });
        });
    });

    // To run: we need to run the StateT, which gives a Reader, then run the Reader
    auto reader_result = comp_combined.run(initial_state);  // reader_result is Reader<Config, tuple<int, int>>
    auto [combined_result, combined_final_state] = reader_result.run(env);
    std::cout << "Combined Result: " << combined_result << ", Combined Final State: " << combined_final_state << std::endl;

    return 0;
}
